#ifndef GAMEENGINE_GEOMETRY_COORDINATESYSTEMS_TRANSFORMER2D_ORIENTATION_HPP
#define GAMEENGINE_GEOMETRY_COORDINATESYSTEMS_TRANSFORMER2D_ORIENTATION_HPP

#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif

//=================================================================================
// Implementation of the Transformer2dOrientation class

//! Default constructor
/*!
 @note Class T should have a default constructor
 */
template <class T>
Transformer2dOrientation<T>::Transformer2dOrientation() {
	// Setup as identity
	matrix_[0][0] = (T)1;
	matrix_[0][1] = (T)0;
	matrix_[1][0] = (T)0;
	matrix_[1][1] = (T)1;
}

//! Constructor
/*!
 *  Builds a 2D transformer that converts orientations from1 and from2 into orientations to1 and to2
 *
 @param from1 The orientation to transform into to1 in the destination coordinate system
 @param from2 The orientation to transform into to2 in the destination coordinate system
 @param to1 The orientation in which from1 should be transformed in the destination coordinate system
 @param to2 The orientation in which from2 should be transformed in the destination coordinate system
 @sa Function set_transformation is called by this constructor
 @note Class T should have a default constructor
 */
template <class T>
Transformer2dOrientation<T>::Transformer2dOrientation(const Vector2d<T>& from1, const Vector2d<T>& from2, const Vector2d<T>& to1, const Vector2d<T>& to2) {
	set_transformation(from1, from2, to1, to2);
}

//! Copy constructor
/*!
 @param rhs The transformer to copy
 @note Class T should have a default constructor
 @note Class T should have an assignment operator
 */
template <class T>
Transformer2dOrientation<T>::Transformer2dOrientation(const Transformer2dOrientation& rhs) {
	// Copy the transformation matrix
	for ( int k = 0; k < 2; ++k ) {
		for ( int l = 0; l < 2; ++l ) {
			matrix_[k][l] = rhs.matrix_[k][l];
		}
	}
}

//! Destructor
/*!
 @note The destructor of class T should be public
 */
template <class T>
Transformer2dOrientation<T>::~Transformer2dOrientation() {}

//! Assignment operator
/*!
 @param rhs The transformer to copy
 @note Class T should have an assignment operator
 */
template <class T>
Transformer2dOrientation<T>& Transformer2dOrientation<T>::operator=(const Transformer2dOrientation& rhs) {
	if ( &rhs != this ) {
		// Copy the transformation matrix
		for ( int k = 0; k < 2; ++k ) {
			for ( int l = 0; l < 2; ++l ) {
				matrix_[k][l] = rhs.matrix_[k][l];
			}
		}
	}
	return *this;
}

//! Setup a two-dimensional transformation
/*!
 @param from1 The orientation to transform into to1 in the destination coordinate system
 @param from2 The orientation to transform into to2 in the destination coordinate system
 @param to1 The orientation in which from1 should be transformed in the destination coordinate system
 @param to2 The orientation in which from2 should be transformed in the destination coordinate system
 @return True if such a transformer exists. If no such transformation can be setup, the transformer is not modified.
 @note Class T should have an assignment operator
 */
template <class T>
bool Transformer2dOrientation<T>::set_transformation(const Vector2d<T>& from1, const Vector2d<T>& from2, const Vector2d<T>& to1, const Vector2d<T>& to2) {
	// Compute denominator
	T den = from2.x()*from1.y() - from1.x()*from2.y();
	if ( den == (T)0 ) return false;

	// Setup matrix
	matrix_[0][0] = ( to2.x()*from1.y() - to1.x()*from2.y() ) / den;
	matrix_[0][1] = ( from2.x()*to1.x() - from1.x()*to2.x() ) / den;
	matrix_[1][0] = -( from2.y()*to1.y() - from1.y()*to2.y() ) / den;
	matrix_[1][1] = ( from2.x()*to1.y() - from1.x()*to2.y() ) / den;
	return true;
}

//! Accessor to the first column of the transformation matrix (read only)
/*!
 @return The first column of the transformation matrix
 */
template <class T>
Vector2d<T> Transformer2dOrientation<T>::column1() const {
	return Vector2d<T>(matrix_[0][0], matrix_[1][0]);
}

//! Accessor to the second column of the transformation matrix (read only)
/*!
 @return The second column of the transformation matrix
 */
template <class T>
Vector2d<T> Transformer2dOrientation<T>::column2() const {
	return Vector2d<T>(matrix_[0][1], matrix_[1][1]);
}

//! Accessor to the first row of the transformation matrix (read only)
/*!
 @return The first row of the transformation matrix
 */
template <class T>
Vector2d<T> Transformer2dOrientation<T>::row1() const {
	return Vector2d<T>(matrix_[0][0], matrix_[0][1]);
}

//! Accessor to the second row of the transformation matrix (read only)
/*!
 @return The second row of the transformation matrix
 */
template <class T>
Vector2d<T> Transformer2dOrientation<T>::row2() const {
	return Vector2d<T>(matrix_[1][0], matrix_[1][1]);
}

//! Accessor to the given index of the transformation matrix (read only)
/*!
 @return The given index of the transformation matrix
 */
template <class T>
T Transformer2dOrientation<T>::matrix(Transformer2DOrientation::Index row, Transformer2DOrientation::Index column) const {
	return matrix_[row][column];
}

//! Accessor to the given index of the transformation matrix (read-write)
/*!
 @return A reference to the given index of the transformation matrix
 */
template <class T>
T& Transformer2dOrientation<T>::matrix(Transformer2DOrientation::Index row, Transformer2DOrientation::Index column) {
	return matrix_[row][column];
}

//! Transform the given orientation from the source space to the destination space
/*!
 @param from The coordinates of the orientation to transform in the source space
 @return The coordinates of the "from" orientation in the destination space
 */
template <class T>
Vector2d<T> Transformer2dOrientation<T>::transform(const Vector2d<T>& from) const {
	return Vector2d<T>(
		matrix_[0][0]*from.x() + matrix_[0][1]*from.y(),
		matrix_[1][0]*from.x() + matrix_[1][1]*from.y()
	);
}

//! Create an inverse transformer, i.e., the transformer that converts orientations from the destination space to the source space
/*!
 @param ok If not nil, receives true if an inverse transformer exists and false otherwise
 @return The inverse transformer. If no such transformer exists, the identity transformer is returned
 */
template <class T>
Transformer2dOrientation<T> Transformer2dOrientation<T>::inverse(bool* ok) const {
	Vector2d<T> p1(1,0);
	Vector2d<T> p2(0,1);
	Transformer2dOrientation res;
	bool b = res.set_transformation(transform(p1),transform(p2),p1,p2);
	if ( ok != nil ) *ok = b;
	return res;
}

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#endif
